package webengine

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"gin-api-server/app"
	"gin-api-server/app/middleware"
	"gin-api-server/core_library/global"

	limit "github.com/aviddiviner/gin-limit"
	"github.com/gin-contrib/pprof"

	"github.com/fatih/color"
	"github.com/gin-gonic/gin"
)

func InitGin() {
	serverConfig := global.Config.Server

	serverDebug := serverConfig.Debug
	// gin.SetMode(gin.DebugMode)
	gin.SetMode(gin.ReleaseMode)
	g := gin.New()
	g.MaxMultipartMemory = int64(global.Config.Upload.MaxSize) * 1024 * 1024
	pprof.Register(g)
	g.Delims("{{", "}}")
	g.LoadHTMLGlob("views/*")
	// 加载公众号校验文件
	wechatMp := global.Config.Wechat.Mp
	if strings.EqualFold(wechatMp.VerfiyFilePath, "") {
		g.StaticFile(wechatMp.VerfiyFilePath, wechatMp.VerfiyFilePath)
	}
	g.Static("static", "./static")
	if strings.EqualFold(serverConfig.BindUrl, "") {
		panic("未配置服务网址 server.bindurl")
	}
	if !serverDebug {
		g.Use(Recover)
	}
	// 限制并发数量
	maxAllowowed := serverConfig.MaxAllowowed
	if maxAllowowed > 0 {
		g.Use(limit.MaxAllowed(maxAllowowed))
	}
	g.Use(GetHandlerLastMethod())
	// 跨域 [放在路由注册之后，那么这个接口将不为跨域接口，也就是说g.Use跨域的时候，必须放在需要跨域的route前面。]

	if global.Config.Cors.Status {
		g.Use(CorsMiddleware())
	}

	// 注册路由
	InitSystemroute(g)
	// 扫描路由
	ScanRoutes()
	registerRoutes(serverConfig.RouteApiPrefix, g, app.ApiRoutes(), []gin.HandlerFunc{middleware.JwtAuth()})
	registerRoutes(serverConfig.RouteBackendPrefix, g, app.BackendRoutes(), []gin.HandlerFunc{middleware.BackendMiddleware()})
	registerRoutes(serverConfig.RouteViewPrefix, g, app.ViewRoutes(), []gin.HandlerFunc{middleware.ViewMiddleware()})
	// 扫描不需要认证的路由
	ScanNoAuthControllerToClassMap(g)

	srv := &http.Server{
		Addr:    fmt.Sprintf("%s:%s", serverConfig.ListenIp, serverConfig.ListenPort),
		Handler: g,
	}

	go func() {
		// 服务连接
		color.Green("Server run on http://127.0.0.1:" + serverConfig.ListenPort)
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("listen: %s\n", err)
		}
	}()

	quit := make(chan os.Signal)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit
	color.Green("Shutdown Server ...")

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	if err := srv.Shutdown(ctx); err != nil {
		color.Red("Server Shutdown:", err)
	}
}

func registerRoutes(prefix string, g *gin.Engine, routes map[string][]app.Routes, handlers []gin.HandlerFunc) {
	group := g.Group(prefix)
	if len(handlers) > 0 {
		group.Use(handlers...)
	}
	for routePrefix, routes := range routes {
		for _, route := range routes {
			method := strings.ToLower(route.Method)
			requestUrl := fmt.Sprintf("%s%s", routePrefix, route.Url)
			switch method {
			case "get":
				group.GET(requestUrl, route.Handler)
			case "post":
				group.POST(requestUrl, route.Handler)
			case "put":
				group.PUT(requestUrl, route.Handler)
			case "delete":
				group.DELETE(requestUrl, route.Handler)
			case "patch":
				group.PATCH(requestUrl, route.Handler)
			case "head":
				group.HEAD(requestUrl, route.Handler)
			case "options":
				group.OPTIONS(requestUrl, route.Handler)
			default:
				group.Any(requestUrl, route.Handler)
			}
		}
	}
}
